home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 June: Reference Library / Dev.CD Jun 00 RL Disk 1.toast / mac / Technical Documentation / Develop / develop Issue 25 / develop Issue 25 code / ToolFrontEnd.sea / ToolFrontEnd / ToolFrontEnd Source / Default Scanner / DefaultScanner.c / DefaultScanner.c
Encoding:
C/C++ Source or Header  |  1996-02-21  |  7.6 KB  |  357 lines  |  [TEXT/CWIE]

  1.  
  2. /* standard headers */
  3. #include <ctype.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6.  
  7. /* system headers */
  8. #include <Strings.h>
  9. #include <TextUtils.h>
  10.  
  11. /* compiler headers */
  12. #include <A4Stuff.h>
  13. #include <DropInCompiler.h>
  14.  
  15. /* project headers */
  16. #include "ToolFrontEnd.h"
  17. #include "FullPath.h"
  18.  
  19.  
  20. pascal OSErr    main(ToolFrontEndStatus* status);
  21. static OSErr    ProcessFile(ToolFrontEndStatus* status, const FSSpec* spec, 
  22.                             Handle hand, long size, Boolean isIncludeFile);
  23. static OSErr    ParseText(ToolFrontEndStatus* status, const char* text);
  24. static OSErr    IncludeFile(ToolFrontEndStatus* status, const char* inclname, Boolean fullSearch);
  25. static OSErr    ReadOneFile(ToolFrontEndStatus* status, const FSSpec* spec, 
  26.                             Handle hand, long size, Boolean isIncludeFile, Handle* textp);
  27.  
  28.  
  29.  
  30. pascal OSErr main(ToolFrontEndStatus* status)
  31. {
  32.     OSErr err;
  33.     
  34.     /* set up global world (68K only) */
  35.     EnterCodeResource();
  36.     
  37.     status->scanStatus = NULL;
  38.     
  39.     err = ProcessFile(status, &status->cpb->sourcefile, status->cpb->sourcehandle,
  40.                         status->cpb->sourcehandlesize, false);
  41.     
  42.     /* tear down global world (68K only) */
  43.     ExitCodeResource();
  44.     
  45.     return err;
  46. }
  47.  
  48.  
  49. static OSErr    ProcessFile(ToolFrontEndStatus* status, const FSSpec* spec, 
  50.                             Handle hand, long size, Boolean isIncludeFile)
  51. {
  52.     Handle    text;
  53.     OSErr    err;
  54.     Byte    state;
  55.     
  56.     /* read in the text & cache it */
  57.     err = ReadOneFile(status, spec, hand, size, isIncludeFile, &text);
  58.     if (err != noErr) return err;
  59.     
  60.     /* process the text */
  61.     state = HGetState(text);
  62.     HLock(text);
  63.     err = ParseText(status, *text);
  64.     HSetState(text, state);
  65.     
  66.     /* release the text */
  67.     (void) CWCompFreeIncludeFile(status->cpb, text);
  68.  
  69.     return err;
  70. }
  71.  
  72.  
  73. static OSErr    ParseText(ToolFrontEndStatus* status, const char* text)
  74. {
  75.     const char    incltok[]    = "include";
  76.     size_t        incllen        = strlen(incltok);
  77.     OSErr        err = noErr;
  78.         
  79.     /*
  80.      *    Process the source file text.
  81.      *
  82.      *  Look for #include statements at the beginning of every line,
  83.      *    then open the specified file and process it recursively.
  84.      */
  85.     
  86.     while ((err == noErr) && (*text != '\0'))
  87.     {
  88.         /* at the top of the loop, we're at the beginning of a line */
  89.         
  90.         char    c;
  91.         
  92.         /* skip white space (but not carriage returns) */
  93.         while (((c = *text) != '\r') && isspace(c))
  94.             text++;
  95.         
  96.         if (c == '#')
  97.         {
  98.             /* preprocessor directive */
  99.             
  100.             text++;
  101.             
  102.             /* skip white space */
  103.             while (((c = *text) != '\r') && isspace(c))
  104.                 text++;
  105.             
  106.             if (strncmp(text, incltok, incllen) == 0)
  107.             {
  108.                 char    delim    = '\0';
  109.                 
  110.                 /* we have #include */
  111.                 text += incllen;
  112.                 
  113.                 /* skip white space (but not carriage returns) */
  114.                 while (((c = *text) != '\r') && isspace(c))
  115.                     text++;
  116.                 
  117.                 if (c == '"')
  118.                     delim = '"';
  119.                 else if (c == '<')
  120.                     delim = '>';
  121.                 
  122.                 if (delim != '\0')
  123.                 {
  124.                     /* we have #include "" or #include <> */
  125.                     
  126.                     const char*    start;
  127.                     const char*    end;
  128.                     char        inclname[100];
  129.                     
  130.                     start = ++text;
  131.                     end = strchr(start, delim);
  132.                     
  133.                     if (end != NULL)
  134.                     {
  135.                         /* we have an #include file name! */
  136.                         
  137.                         if (end - start >= sizeof(inclname))
  138.                             end = start + sizeof(inclname) + 1;
  139.                         
  140.                         memcpy(inclname, start, end - start);
  141.                         inclname[end - start] = '\0';
  142.                         
  143.                         err = IncludeFile(status, inclname, (delim == '"'));
  144.                         
  145.                         text = end;
  146.                     }
  147.                 }
  148.             }
  149.         }
  150.         
  151.         /* skip to end-of-line */
  152.         while ((c = *text) != '\r')
  153.             text++;
  154.         
  155.         if (c == '\r')
  156.         {
  157.             /* start a new line */
  158.             
  159.             text++;
  160.             status->linecount++;
  161.             
  162.             if ((status->linecount == 1) || (status->linecount % 50 == 0))
  163.             {
  164.                 /*
  165.                  *    We don't want to call this for every line, 
  166.                  *    'cause it will slow down compilation to a crawl.
  167.                  */
  168.                 
  169.                 err = CWCompDisplayLines(status->cpb, status->linecount);
  170.             }
  171.             
  172.             continue;
  173.         }
  174.     }
  175.         
  176.     return err;
  177. }
  178.  
  179.  
  180. static OSErr    IncludeFile(ToolFrontEndStatus* status, const char* inclname, Boolean fullSearch)
  181. {
  182.     FSSpec    spec;
  183.     Handle    hand;
  184.     long    size;
  185.     Str255    pname;
  186.     Boolean    alreadyincluded;
  187.     OSErr    err;
  188.     int        i;
  189.         
  190.     // convert C string to pascal
  191.     for (i = 0; inclname[i] != 0 && i < 255; i++)
  192.         pname[i + 1] = inclname[i];
  193.     pname[0] = i;
  194.     
  195.     /* locate the file name using the project's access paths */
  196.     err = CWCompFindIncludeFile(status->cpb, pname, fullSearch, &hand, &size, &spec, 
  197.                                 &alreadyincluded, false);
  198.                                 
  199.     if (err == noErr && !alreadyincluded)
  200.     {
  201.         // add the folder of this file to the search path argument list
  202.         int i;
  203.         Boolean found = false;
  204.         
  205.         // DebugStr(pname);
  206.         
  207.         for (i = 0; i < status->numFolderPaths; i++)
  208.         {
  209.             // compare the vRefNum and parID
  210.             if (spec.vRefNum == status->folderPaths[i].vRefNum
  211.                 && spec.parID == status->folderPaths[i].dirID)
  212.             {
  213.                 found = true;
  214.                 break;
  215.             }
  216.         }
  217.         
  218.         if (!found)
  219.         {
  220.             // not already in list -- add it
  221.             Handle dirName;
  222.             short dirNameLength;
  223.             
  224.             if (status->numFolderPaths >= MAXFOLDERPATHS)
  225.             {
  226.                 // too many folders error -- fat chance!
  227.                 CWCompErrorMessage(status->cpb, "Too many include file folders.");
  228.                 err = paramErr;
  229.  
  230.             }
  231.  
  232.             // add to list
  233.             if (err == noErr)
  234.                 err = GetFullPath(spec.vRefNum, spec.parID, NULL, &dirNameLength, &dirName);
  235.             if (err == noErr)
  236.             {
  237.                 status->folderPaths[status->numFolderPaths].path = dirName;
  238.                 status->folderPaths[status->numFolderPaths].vRefNum = spec.vRefNum;
  239.                 status->folderPaths[status->numFolderPaths].dirID = spec.parID;
  240.                 ++status->numFolderPaths;
  241.             }
  242.         }
  243.         
  244.         err = ProcessFile(status, &spec, hand, size, true);
  245.     }
  246.     else if (err == fnfErr)
  247.     {
  248.         err = noErr; // it's not really an error -- and I don't see a CW warning API....
  249. #if 0
  250.         char    errmsg[200];
  251.         
  252.         sprintf(errmsg, "Can't locate file \"%s\".", inclname);
  253.         
  254.         err = CWCompErrorMessage(status->cpb, errmsg);
  255. #endif
  256.     }
  257.     
  258.     return (err);
  259. }
  260.  
  261.  
  262. static OSErr    ReadOneFile(ToolFrontEndStatus* status, const FSSpec* spec, 
  263.                             Handle hand, long size, Boolean isIncludeFile, Handle* textp)
  264. {
  265.     Boolean    textIsCached    = false;
  266.     Handle    text;
  267.     OSErr    err;
  268.     
  269.     if (hand != NULL)
  270.     {
  271.         /*
  272.          *    The file is open in the editor.  We have to use 'size' to determine the 
  273.          *    number of characters to read, because the editor may have appended slop 
  274.          *    bytes to the end of the text.
  275.          *
  276.          *    For simplicity's sake, we'll just copy the text into the temporary buffer, 
  277.          *    just as we do for files we read from disk.
  278.          */
  279.         
  280.         text = NewHandle(size+1);
  281.         if (text == NULL)
  282.             return (memFullErr);
  283.         
  284.         BlockMoveData(*hand, *text, size);
  285.         (*text)[size] = '\0';
  286.     }
  287.     else
  288.     {
  289.         /*
  290.          *    The file isn't open in the editor.  If this is an include file, then look 
  291.          *    for it in the include file cache.
  292.          */
  293.         
  294.         if (isIncludeFile && status->cpb->caching_includes)
  295.         {
  296.             err = CWCompGetCachedIncludeFile(status->cpb, spec, &text);
  297.             textIsCached = (err == noErr);
  298.         }
  299.         else
  300.             err = fnfErr;
  301.         
  302.         if (err != noErr)
  303.         {
  304.             /*
  305.              *    The file was in the cache, so we'll have to hit the disk.
  306.              */
  307.             
  308.             short    refnum;
  309.             
  310.             err = FSpOpenDF(spec, fsRdPerm, &refnum);
  311.             if (err != noErr)
  312.                 return (err);
  313.             
  314.             err = GetEOF(refnum, &size);
  315.             if (err != noErr)
  316.             {
  317.                 FSClose(refnum);
  318.                 return (err);
  319.             }
  320.             
  321.             text = NewHandle(size+1);
  322.             if (text == NULL)
  323.             {
  324.                 FSClose(refnum);
  325.                 return (err);
  326.             }
  327.             
  328.             HLock(text);
  329.             err = FSRead(refnum, &size, *text);
  330.             FSClose(refnum);
  331.             
  332.             if (err != noErr)
  333.             {
  334.                 DisposeHandle(text);
  335.                 return (err);
  336.             }
  337.             
  338.             HUnlock(text);
  339.             (*text)[size] = '\0';
  340.         }
  341.     }
  342.  
  343.     /*
  344.      *    At this point, 'text' contains a null-terminated version of our source file.
  345.      *    If it's an include file that hasn't been cached already, then cache it.
  346.      */
  347.     
  348.     if (isIncludeFile && status->cpb->caching_includes && !textIsCached)
  349.     {
  350.         err = CWCompCacheIncludeFile(status->cpb, spec, text);
  351.     }
  352.     
  353.     *textp = text;
  354.     
  355.     return (noErr);
  356. }
  357.